home *** CD-ROM | disk | FTP | other *** search
- #! /usr/local/bin/perl
- #
- # soac - DNS authority records (SOA) checker
- #
- # invoke as:
- # soac [-l msglevel]
- #
- # Copyright (C) 1992, 1993 PUUG - Grupo Portugues de Utilizadores
- # do Sistema UNIX
- # 1992, 1993 FCCN - Fundacao para o Desenvolvimento dos Meios
- # Nacionais de Calculo Cientifico
- #
- # Authors: Jorge Frazao de Oliveira <frazao@puug.pt>
- # Artur Romao <artur@dns.pt>
- #
- # This file is part of the DDT package, Version 2.0.
- #
- # Permission to use, copy, modify, and distribute this software and its
- # documentation for any purpose and without any fee is hereby granted,
- # provided that the above copyright notice appear in all copies. Neither
- # PUUG nor FCCN make any representations about the suitability of this
- # software for any purpose. It is provided "as is" without express or
- # implied warranty.
-
-
- # =()<push(@INC, "@<LIBDIR>@");>()=
- push(@INC, "/usr/local/lib/ddt/cmd");
-
- require "ddt.pl";
-
- # Default values for SOA timers.
- $TopLevel{"Refresh"} = 86400; # 24h
- $TopLevel{"Retry"} = 7200; # 2h
- $TopLevel{"Expire"} = 2592000; # 30d
- $TopLevel{"TTL"} = 345600; # 4d
- $Other{"Refresh"} = 28800; # 8h
- $Other{"Retry"} = 7200; # 2h
- $Other{"Expire"} = 604800; # 7h
- $Other{"TTL"} = 86400; # 1d
-
- $diffTopLevel{"Refresh"} = 0;
- $diffTopLevel{"Retry"} = 0;
- $diffTopLevel{"Expire"} = 0;
- $diffTopLevel{"TTL"} = 0;
-
- $diffOther{"Refresh"} = 0;
- $diffOther{"Retry"} = 0;
- $diffOther{"Expire"} = 0;
- $diffOther{"TTL"} = 0;
-
- $Timeout = 1;
-
- # =()<&read_config("@<SOACONFIG>@");>()=
- &read_config("/usr/local/lib/ddt/cmd/SOA-timers");
-
-
- while (<STDIN>) {
- next if /^;/; # ignore commented lines
-
- chop; # strip record separator
- @Field = split(/\s+/, $_); # break the input line
-
- if (/^\$ORIGIN/) {
- $Origin = $Field[2]; # set to a different origin
-
- next;
- }
-
- if (/^[*\.\-0-9A-Za-z]+/) {
- $LineName = 1;
-
- $Name = &make_name($Field[1], $Origin);
- }
-
- if (/\tIN\tSOA\t/) {
- $saveLine = $_;
-
- &show_zone($Zone);
-
- undef %NS;
-
- $Zone = $Name;
-
- if ($saveLine =~ /\(\s*$/) {
- chop ($_ = <STDIN>);
- }
- else {
- $_ = $saveLine;
- }
-
- # get the timers for this zone
- $_ =~ /(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+).*\)$/;
-
- $SerialNo = $1;
- $Refresh = $2;
- $Retry = $3;
- $Expire = $4;
- $DefaultTTL = $5;
- }
- elsif (/\tIN\tNS\t/) {
- if ($Name eq $Zone) {
- $NS{$Field[$#Field]} = 1;
- }
- }
- }
-
- &show_zone($Zone);
-
- exit 0;
-
-
- sub read_config {
- local($file) = @_;
- local($value);
-
- if(open(CONFIG, $file)) {
- while (<CONFIG>) {
- next if !/\s*(\d+)/;
-
- $value = $1;
-
- $_ = &toupper($_);
-
- if (/^T_REFRESH/) {
- $TopLevel{"Refresh"} = $value;
- }
- elsif (/^T_RETRY/) {
- $TopLevel{"Retry"} = $value;
- }
- elsif (/^T_EXPIRE/) {
- $TopLevel{"Expire"} = $value;
- }
- elsif (/^T_TTL/) {
- $TopLevel{"TTL"} = $value;
- }
- elsif (/^REFRESH/) {
- $Other{"Refresh"} = $value;
- }
- elsif (/^RETRY/) {
- $Other{"Retry"} = $value;
- }
- elsif (/^EXPIRE/) {
- $Other{"Expire"} = $value;
- }
- elsif (/^TTL/) {
- $Other{"TTL"} = $value;
- }
- elsif (/^DIFFT_REFRESH/) {
- $diffTopLevel{"Refresh"} = $value;
- }
- elsif (/^DIFFT_RETRY/) {
- $diffTopLevel{"Retry"} = $value;
- }
- elsif (/^DIFFT_EXPIRE/) {
- $diffTopLevel{"Expire"} = $value;
- }
- elsif (/^DIFFT_TTL/) {
- $diffTopLevel{"TTL"} = $value;
- }
- elsif (/^DIFFREFRESH/) {
- $diffOther{"Refresh"} = $value;
- }
- elsif (/^DIFFRETRY/) {
- $diffOther{"Retry"} = $value;
- }
- elsif (/^DIFFEXPIRE/) {
- $diffOther{"Expire"} = $value;
- }
- elsif (/^DIFFTTL/) {
- $diffOther{"TTL"} = $value;
- }
- elsif (/^TIMEOUT/) {
- $Timeout = $value;
- }
- }
-
- delete $opened{$file} && close($file);
- }
- else {
- warn "Can't open $file: $!\n";
- }
- }
-
-
- #
- # the absolute value of a number
- #
- sub abs {
- local($value) = @_;
-
- return $value < 0 ? -$value : $value;
- }
-
-
- #
- # check each of the timers for their convenience, according to the values read
- # from $ConfigFile (or the default ones, listed at the begining of this file
- #
- sub check_SOA {
- local($zone) = @_;
- local(@Msg, $msg, $fmt);
- local($rref, $dref, $rret, $dret, $rexp, $dexp, $rttl, $dttl);
-
- if ($Level >= 3) {
- if ($zone =~ tr/\./\./ == 1) { # top level domain
- $rref = $TopLevel{"Refresh"};
- $dref = $diffTopLevel{"Refresh"};
-
- $rret = $TopLevel{"Retry"};
- $dret = $diffTopLevel{"Retry"};
-
- $rexp = $TopLevel{"Expire"};
- $dexp = $diffTopLevel{"Expire"};
-
- $rttl = $TopLevel{"TTL"};
- $dttl = $diffTopLevel{"TTL"};
- }
- else { # non-top level domain
- $rref = $Other{"Refresh"};
- $dref = $diffOther{"Refresh"};
-
- $rret = $Other{"Retry"};
- $dret = $diffOther{"Retry"};
-
- $rexp = $Other{"Expire"};
- $dexp = $diffOther{"Expire"};
-
- $rttl = $Other{"TTL"};
- $dttl = $diffOther{"TTL"};
- }
-
- $fmt = "%s%-12s %8d [recommended value: %8d]";
-
- if (&abs($Refresh - $rref) gt $dref) {
- push(@Msg,
- sprintf($fmt, $Lpad[3], "Refresh", $Refresh, $rref));
- }
-
- if (&abs($Retry - $rret) gt $dret) {
- push(@Msg,
- sprintf($fmt, $Lpad[3], "Retry", $Retry, $rret));
- }
-
- if (&abs($Expire - $rexp) gt $dexp) {
- push(@Msg,
- sprintf($fmt, $Lpad[3], "Expire", $Expire, $rexp));
- }
-
- if (&abs($DefaultTTL - $rttl) gt $dttl) {
- push(@Msg,
- sprintf($fmt, $Lpad[3], "Default TTL", $DefaultTTL, $rttl));
- }
-
- if ($#Msg) {
- print " SOA Record";
- foreach $msg ($[ .. $#Msg) {
- print shift(@Msg);
- }
-
- print "";
- }
- }
- }
-
-
- #
- # call dig to see the SOA record for this zone, according to $server
- #
- sub dig {
- local($server, $zone) = @_;
- local($exists, $auth);
-
- chop $server if $server =~ /[.][0-9]*[.]$/; # cut trailing dot
- # from IP address
-
- # =()< $dig = "@<DIG>@";>()=
- $dig = "/usr/local/bin/dig";
-
- open(DIG, "$dig @$server $zone SOA +pfset=0x2220 +norec +time=$Timeout 2>&1 |");
-
- while(<DIG>) {
- chop;
-
- $exists = 1; # dig said something...
-
- if (/^;; flags:.*\baa\b/) {
- $auth = 1; # authoritative answer
- }
-
- if (/^; Bad server/ && $Level >= 1) {
- return sprintf("%s%-20s [Bad server]",
- $Lpad[1], $server);
- }
-
- if (/Connection (.*)/ && $Level >= 4) {
- return sprintf("%s%-20s [Connection %s]",
- $Lpad[4], $server, $1);
- }
-
- if (/(\d+)\s*;serial$/ && $SerialNo != $1 && $Level >= 3) {
- return sprintf("%s%-20s [Serial number mismatch (cached:%d, current:%d)]",
- $Lpad[3], $server, $SerialNo, $1);
- }
- }
-
- if ((!$exists || !$auth) && $Level >= 1) {
- return sprintf("%s%-20s [Non-authoritative answer]",
- $LPad[1], $server);
- }
- }
-
-
- sub check_NS {
- local($zone) = @_;
- local($ns, @Msg, $msg);
-
- if ($#NS == 1 && $Level >= 1) { # this is dangerous
- push(@Msg, "$Lpad[1]$zone has only one name server\n");
- }
-
- foreach $ns (keys %NS) { # check each of the name
- if ($msg = &dig($ns, $zone)) { # servers for authority
- push(@Msg, $msg); # information
- }
- }
-
- if ($#Msg) {
- print " Name Servers";
-
- foreach $msg ($[ .. $#Msg) {
- print shift(@Msg);
- }
-
- print "";
- }
- }
-
-
- sub show_zone {
- local($zone) = @_;
-
- if ($zone ne "") {
- print "\n ###", &toupper($zone), "###\n";
-
- &check_SOA($zone);
- &check_NS($zone);
- }
- }
-